package com.siderakis.orgunit.client.ui;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.CompositeCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.HasCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTree;
import com.google.gwt.user.cellview.client.TreeNode;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasOneWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.TreeViewModel;
import com.siderakis.orgunit.client.domain.OrgUnit;

public class OrgUnitAccessSettings extends Composite {

  private static OrgUnitAccessSettingsUiBinder uiBinder = GWT
      .create(OrgUnitAccessSettingsUiBinder.class);

  interface OrgUnitAccessSettingsUiBinder extends UiBinder<Widget, OrgUnitAccessSettings> {
  }

  private OrgUnit orgName;
  private List<OrgUnit> list;

  public OrgUnitAccessSettings(List<OrgUnit> list, OrgUnit orgName) {
    this.orgName = orgName;
    this.list = list;
    initWidget(uiBinder.createAndBindUi(this));

    // Create a model for the tree.
    TreeViewModel model = new CustomTreeModel(list, orgName);

    CellTree.Resources resource = GWT.create(TreeResources.class);

    CellTree tree = new CellTree(model, "", resource);

    center.setWidget(tree);

    openchildren(tree.getRootTreeNode());

  }

  @UiHandler("next")
  public void onNextClick(ClickEvent event) {
    List<OrgUnit> selected = new ArrayList<OrgUnit>();
    if (orgName.isOn())
      selected.add(orgName);
    for (OrgUnit o : list) {
      if (o.isOn()) {
        selected.add(o);
      }
    }

    String callback = Window.Location.getParameter("callback");
    Window.Location.assign(callback);
  }

  @UiField
  HasOneWidget center;

  public void openchildren(TreeNode treeNode) {
    if (treeNode != null)
      for (int i = 0; i < treeNode.getChildCount(); i++)
        openchildren(treeNode.setChildOpen(i, true));

  }

  interface TreeResources extends CellTree.Resources {
    @Source("OrgTreeStyle.css")
    CellTree.Style cellTreeStyle();
  }

  private static CompositeCell<OrgUnit> createComposite() {
    List<HasCell<OrgUnit, ?>> hasCells = new ArrayList<HasCell<OrgUnit, ?>>();

    hasCells.add(new HasCell<OrgUnit, OrgUnit>() {

      private OrgUnitCell cell = new OrgUnitCell();

      public Cell<OrgUnit> getCell() {
        return cell;
      }

      public FieldUpdater<OrgUnit, OrgUnit> getFieldUpdater() {
        return null;
      }

      public OrgUnit getValue(OrgUnit object) {
        return object;
      }
    });

    hasCells.add(new HasCell<OrgUnit, OrgUnit>() {

      private AccessToggleCell cell = new AccessToggleCell();

      @Override
      public Cell<OrgUnit> getCell() {
        return cell;
      }

      @Override
      public FieldUpdater<OrgUnit, OrgUnit> getFieldUpdater() {
        return null;
      }

      @Override
      public OrgUnit getValue(OrgUnit object) {
        return object;
      }
    });

    CompositeCell<OrgUnit> a = new CompositeCell<OrgUnit>(hasCells) {
      protected <X> void render(Context context, OrgUnit value, SafeHtmlBuilder sb,
          HasCell<OrgUnit, X> hasCell) {
        Cell<X> cell = hasCell.getCell();
        sb.appendHtmlConstant("<span class='cf'>");
        cell.render(context, hasCell.getValue(value), sb);
        sb.appendHtmlConstant("</span>");
      }

    };

    return a;
  }

  private static class CustomTreeModel implements TreeViewModel {

    private List<OrgUnit> list;
    private OrgUnit org;

    public CustomTreeModel(List<OrgUnit> list, OrgUnit orgName) {
      this.list = list;
      this.org = orgName;
    }

    public <T> NodeInfo<?> getNodeInfo(T value) {
      ListDataProvider<OrgUnit> dataProvider = new ListDataProvider<OrgUnit>();
      List<OrgUnit> node = new ArrayList<OrgUnit>();
      if (value == null) {
        // skip null
      } else if (value.equals("")) {

        node.add(org);
      } else {
        for (OrgUnit o : list) {
          if (((OrgUnit) value).getPath().equals(o.getParentPath()))
            node.add(o);
        }
      }
      dataProvider.setList(node);
      return new DefaultNodeInfo<OrgUnit>(dataProvider, createComposite());
    }

    public boolean isLeaf(Object value) {
      if (value == null)
        return list.isEmpty();
      if (value instanceof OrgUnit) {
        for (OrgUnit o : list) {
          if (((OrgUnit) value).getPath().equals(o.getParentPath()))
            return false;
        }
        return true;
      }
      return false;
    }
  }
}
